About 7359 letters
About 37 minutes
Source code: https://github.com/hubenchang0515/QtTheme/
Qt Theme is a pure QSS-based Qt theme project that allows you to easily improve the styling of existing projects.
It supports C++, PyQt5, PyQt6, PySide2, PySide6, and is also published as WebAssembly on GitHub Pages.
Here is a demonstration of usage in Python. First, install it:
pip install QtTheme
Let Deep Seek randomly generate a simple interface example for me:
import sys
from PySide6.QtWidgets import *
from PySide6.QtGui import QPixmap
from PySide6.QtCore import Qt, QTimer
class DemoWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("PyQt Widget Demo Interface")
self.setGeometry(100, 100, 800, 600)
# Create central widget and main layout
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
# Add functional sections
self.create_input_section(main_layout)
self.create_selection_section(main_layout)
self.create_display_section(main_layout)
self.create_progress_section(main_layout)
# Add status bar
self.statusBar().showMessage("Ready")
# Initialize progress value
self.progress_value = 0
self.update_progress()
def create_input_section(self, layout):
group = QGroupBox("Input Controls")
grid = QGridLayout()
# Single line text input
self.line_edit = QLineEdit()
self.line_edit.setPlaceholderText("Single line text input...")
grid.addWidget(QLabel("Single Line Text:"), 0, 0)
grid.addWidget(self.line_edit, 0, 1)
# Multi-line text input
self.text_edit = QTextEdit()
self.text_edit.setPlaceholderText("Multi-line text input...")
grid.addWidget(QLabel("Multi-line Text:"), 1, 0)
grid.addWidget(self.text_edit, 1, 1)
# Number input
self.spin_box = QSpinBox()
self.spin_box.setRange(0, 100)
grid.addWidget(QLabel("Number Input:"), 2, 0)
grid.addWidget(self.spin_box, 2, 1)
group.setLayout(grid)
layout.addWidget(group)
def create_selection_section(self, layout):
group = QGroupBox("Selection Controls")
hbox = QHBoxLayout()
# Checkboxes
vbox = QVBoxLayout()
self.check1 = QCheckBox("Option 1")
self.check2 = QCheckBox("Option 2")
vbox.addWidget(self.check1)
vbox.addWidget(self.check2)
hbox.addLayout(vbox)
# Radio buttons
vbox = QVBoxLayout()
self.radio1 = QRadioButton("Radio 1")
self.radio2 = QRadioButton("Radio 2")
self.radio1.setChecked(True)
vbox.addWidget(self.radio1)
vbox.addWidget(self.radio2)
hbox.addLayout(vbox)
# Combo box
self.combo = QComboBox()
self.combo.addItems(["Option A", "Option B", "Option C"])
hbox.addWidget(self.combo)
group.setLayout(hbox)
layout.addWidget(group)
def create_display_section(self, layout):
group = QGroupBox("Display Controls")
hbox = QHBoxLayout()
# Label
self.label = QLabel("This is a label")
self.label.setAlignment(Qt.AlignCenter)
self.label.setStyleSheet("border: 1px solid gray; padding: 10px;")
hbox.addWidget(self.label)
# Image display
pixmap = QPixmap(100, 50)
pixmap.fill(Qt.blue)
image_label = QLabel()
image_label.setPixmap(pixmap)
hbox.addWidget(image_label)
# List widget
self.list_widget = QListWidget()
self.list_widget.addItems(["Item 1", "Item 2", "Item 3"])
hbox.addWidget(self.list_widget)
group.setLayout(hbox)
layout.addWidget(group)
def create_progress_section(self, layout):
group = QGroupBox("Progress Controls")
vbox = QVBoxLayout()
# Progress bar
self.progress_bar = QProgressBar()
self.progress_bar.setValue(0)
vbox.addWidget(self.progress_bar)
# Slider
self.slider = QSlider(Qt.Horizontal)
self.slider.setRange(0, 100)
self.slider.valueChanged.connect(self.on_slider_changed)
vbox.addWidget(self.slider)
# Control buttons
btn_layout = QHBoxLayout()
self.start_btn = QPushButton("Start Progress")
self.start_btn.clicked.connect(self.start_progress)
self.reset_btn = QPushButton("Reset")
self.reset_btn.clicked.connect(self.reset_progress)
btn_layout.addWidget(self.start_btn)
btn_layout.addWidget(self.reset_btn)
vbox.addLayout(btn_layout)
group.setLayout(vbox)
layout.addWidget(group)
def on_slider_changed(self, value):
self.progress_bar.setValue(value)
self.statusBar().showMessage(f"Slider Value: {value}")
def start_progress(self):
self.timer = QTimer()
self.timer.timeout.connect(self.update_progress)
self.timer.start(100)
def update_progress(self):
self.progress_value += 1
if self.progress_value > 100:
self.timer.stop()
return
self.progress_bar.setValue(self.progress_value)
self.slider.setValue(self.progress_value)
def reset_progress(self):
self.progress_value = 0
self.progress_bar.setValue(0)
self.slider.setValue(0)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = DemoWindow()
window.show()
sys.exit(app.exec())
Run it and see:
Import QtTheme and apply the style:
import QtTheme.PySide6 as QtTheme
class DemoWindow(QMainWindow):
def __init__(self):
# omitted...
# Set global stylesheet
self.setStyleSheet(QtTheme.getThemeStyle('Flat', 'Dark', 'Blue', 'Pink'))
Finally, set colors on widgets as needed via QWidget.setProperty
:
def create_progress_section(self, layout):
# omitted...
# Set colors for buttons
self.start_btn.setProperty("Color", "Primary")
self.reset_btn.setProperty("Color", "Danger")
You can also skip installing QtTheme
and export resources via the online page, then include them in your project using RCC:
pyside6-rcc -o resource.py QtTheme.qrc
Just modify the import style, keep other code unchanged:
from PySide6.QtCore import QFile
import resource # import the generated resource.py
class DemoWindow(QMainWindow):
def __init__(self):
# omitted...
qss = QFile(":/QtTheme/theme/Flat/Dark/Blue/Pink.qss")
qss.open(QFile.OpenModeFlag.ReadOnly)
self.setStyleSheet(qss.readAll().data().decode())
Created in 5/15/2025
Updated in 5/15/2025